/**************************************************************************
	File		: osal_log.c
	Author		: TaoLei Zhang
	Date		: 2018-9-18
***************************************************************************/

	
/**************************************************************************
    								include
***************************************************************************/
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/slab.h>

#include "osal_log.h"
#include "osal_fs.h"
/**************************************************************************
    								macro
***************************************************************************/
 
/**************************************************************************
    								typedef
***************************************************************************/

/**************************************************************************
    								variables
***************************************************************************/
static LogLevel_e g_DefaultLogLevel = Log_Error;
static OsalProcHandle g_LogDirHdl = NULL;


/**************************************************************************
    								functions
***************************************************************************/
static ssize_t logLevelRead(struct file *file, char __user *buf, size_t size, loff_t *ppos)

{
	int len = 0;

	if (*ppos > 0) 
	{
		return 0;
	}

	len = sprintf(buf, "%d\n",  g_DefaultLogLevel);
	*ppos += 1;
	return len;

}

static ssize_t logLevelWrite(struct file *file, const char __user *buf, size_t size, loff_t *_pos)
{
	char k_buf[4];
	char *endp;
	unsigned long value;
	int count = (4 > size) ? size : 4;
	int ret;

	if (copy_from_user(k_buf, buf, count)) 
	{
		ret = -EFAULT;
		goto err;

	}
	else 
	{

		value = simple_strtoul(k_buf, &endp, 10);
		if (value < Log_Debug || value > Log_Fatal) 
		{
			ret = -EINVAL;
			goto err;

		}

		g_DefaultLogLevel = value;
		
		return count;
	}
	
err: 
	return ret;

}

static struct file_operations g_OsalLogLevelOps = {
	.owner = THIS_MODULE,
	.read = logLevelRead,
	.write = logLevelWrite,
};



void OsalLog_(LogLevel_e level, char *fmt, ...)
{
	if (level >= g_DefaultLogLevel)
	{
		va_list args;
		char *pLevel;

		switch(level)
		{
			case Log_Debug:	pLevel = "[Debug]";		break;
			case Log_Info:		pLevel = "[Info]";		break;
			case Log_Warn:		pLevel = "[Warn]";		break;
			case Log_Error:	pLevel = "[Error]";		break;
			case Log_Fatal:	pLevel = "[Fatal]";		break;
			default:			pLevel = "[Unknow]";	break;
		}

		va_start(args, fmt);
		vprintk(fmt, args);
		va_end(args);
	}
}
EXPORT_SYMBOL(OsalLog_);


int osal_log_init(void)
{
	OsalProcHandle defaultLogLevel;

	g_LogDirHdl = OsalProcMkdir("osal_log", NULL);
	if (NULL == g_LogDirHdl)
	{
		printk("can not create /proc/osal_log dir.\n");
		return -EIO;
	}

	defaultLogLevel = OsalProcCreateFile("defaultLogLevel", S_IRUGO | S_IFREG, g_LogDirHdl, &g_OsalLogLevelOps, NULL);
	if (NULL == defaultLogLevel)
	{
		printk("can not create /proc/osal_log/defaultLogLevel, ignore.\n");
	}
	
	return 0;
}
EXPORT_SYMBOL(osal_log_init);


void osal_log_exit(void)
{
	OsalProcRemoveFile("defaultLogLevel", g_LogDirHdl);
	OsalProcRemoveDir("osal_log", NULL);
}
EXPORT_SYMBOL(osal_log_exit);

